import { EventEmitter } from "stream";
import { MyServer } from "./MyServer";
import { WebSocketServer ,WebSocket} from "ws";
import { buffer } from "stream/consumers";
import { ApiMsgEnum, binaryDecode, binaryEncode, IModel, strdecode, strencode } from "../Common";
import { buffer2ArrayBuffer } from "../Utils";

// 定义回调函数接口
interface IItem {
    cb: Function;
    ctx: unknown;
}
/**
 * Connection类是对socket对象的封装
 * 因为socket收到message后需要转换为字符串，再JSON.parse，再拿到data
 * 这个过程跟之后的业务逻辑没有什么关系，所以单独提出来
 */
export class Connection extends EventEmitter{
    // 存储消息监听器的映射表
    private msgMap: Map<ApiMsgEnum, Array<IItem>> = new Map();
    
    constructor(private server:MyServer,private ws:WebSocket){
        super()
        this.ws.on("close",()=>{
            
            this.emit("close")
        })
        this.ws.on("message",(buffer:Buffer)=>{
            // const ta = new Uint8Array()
            // const ta = new Uint8Array(buffer)
            // const str =strdecode(ta)
            // const str  = buffer.toString()
            //客户端发送的数据可能不是有效的 JSON 格式，所以需要使用 try catch 来捕获错误
            try {
                // 将字符串转换为对象
                // const msg = JSON.parse(str)
                const msg = binaryDecode(buffer2ArrayBuffer(buffer))
                // 结构msg
                const {name,data}=msg
                // 检查客户端发的name在不在apiMap的key中
                if(this.server.apiMap.has(name)){
                    try {
                         // 获取API处理函数，这里的cb是setapi中的箭头函数
                        const cb = this.server.apiMap.get(name)
                        //箭头函数的返回值，调用cb方法,参数为自己的connection和data，第一个null表示不需要指定上下文
                        const res = cb.call(null,this,data)
                        //发送返回值给客户端
                        this.sendMsg(name,{
                            success:true,
                            res,
                        })
                    } catch (e) {
                        //如果箭头函数的返回值是抛出的异常，则发送异常信息
                        this.sendMsg(name,{
                            success:true,
                            error:e.message,
                        })
                    }
                   
                }else{
                    try {
                        // 如果不是API请求，则作为普通消息处理
                    if (this.msgMap.has(name)) {
                        this.msgMap.get(name).forEach(({ cb, ctx }) => {
                            cb.call(ctx,this, data);
                        });
                    } 
                    } catch (error) {
                        console.log(error)
                    }
                    
                }
                
            } catch (e) {
                console.log(e)
            }
        })
    }

    

    /**
     * 发送消息给客户端
     */
    sendMsg<T extends keyof IModel['msg']>(name:T,data:IModel["msg"][T]){
        //结构化数据
        const msg = {
            name,
            data,
        }
        const da = binaryEncode(name,data)
        // const str = JSON.stringify(msg)
        // const ta = strencode(str)
        // Node.js可以直接用 Buffer.from(ta) 把 Uint8Array 或字节数组转成 Buffer
        // const buffer= Buffer.from(ta)
        const buffer= Buffer.from(da.buffer)
        //发送消息，json.stringify将对象转换为字符串
        this.ws.send(buffer)
        // this.ws.send(JSON.stringify(msg))
    }
    // 监听特定类型的消息
    //跟eventManager的on方法很像,绑定名字，注册回调，绑定上下文
    listenMsg<T extends keyof IModel['msg']>(name:T,cb:(connection:Connection ,args:IModel['msg'][T])=>void,ctx:unknown){
        // 如果已存在该类型的监听器，则添加到数组中
        if (this.msgMap.has(name)) {
            this.msgMap.get(name).push({ cb, ctx });
        } else {
            // 如果不存在，则创建新的监听器数组
            this.msgMap.set(name, [{ cb, ctx }]);
        }
    }

    //解绑类似off方法
    unlistenMsg<T extends keyof IModel['msg']>(name:T,cb:(connection:Connection ,args:IModel['msg'][T])=>void,ctx:unknown){
        if (this.msgMap.has(name)) {
            const index = this.msgMap.get(name).findIndex((i) => cb === i.cb && i.ctx === ctx);
            index > -1 && this.msgMap.get(name).splice(index, 1);
          }
    }
}